from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse
from django.utils import timezone
from django.views.generic import TemplateView, DetailView, ListView
from django.views import View
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q, Count, Avg
from django.core.paginator import Paginator

from analysis.services import ProfileService, AnalysisService
from analysis.models import KnowledgeMasteryProfile, KnowledgePracticeRecord
from score.models import ExamRecord, ScoreLossDetail, Subject, KnowledgePoint


class KnowledgeProfileDashboardView(LoginRequiredMixin, TemplateView):
    """知识点画像仪表板 - 主页面"""
    template_name = 'analysis/profile_dashboard.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        student = self.request.user.student

        profile_service = ProfileService()
        analysis_service = AnalysisService()

        # 获取所有知识点画像
        profiles = profile_service.get_student_profile(student)

        # 按科目分组
        subjects_data = {}
        for profile in profiles:
            subject_name = profile.knowledge_point.subject.name
            if subject_name not in subjects_data:
                subjects_data[subject_name] = {
                    'profiles': [],
                    'avg_mastery': 0,
                    'total_points': 0,
                    'mastered_count': 0
                }

            subjects_data[subject_name]['profiles'].append(profile)

        # 计算每个科目的统计数据
        for subject_name, data in subjects_data.items():
            profiles_list = data['profiles']
            data['total_points'] = len(profiles_list)
            data['mastered_count'] = len([p for p in profiles_list if p.mastery_level >= 0.8])
            if profiles_list:
                data['avg_mastery'] = sum(p.mastery_level for p in profiles_list) / len(profiles_list)

        # 获取学习洞察
        insights = analysis_service.get_learning_insights(student)

        # 获取薄弱知识点（前5个）
        weak_points = profile_service.get_weak_points(student, threshold=0.6)[:5]

        # 需要复习的知识点
        need_review = profiles.filter(
            Q(next_review_date__isnull=False) &
            Q(next_review_date__lte=timezone.now().date())
        )[:5]

        context.update({
            'subjects_data': subjects_data,
            'total_knowledge_points': profiles.count(),
            'mastered_count': profiles.filter(mastery_level__gte=0.8).count(),
            'weak_count': profiles.filter(mastery_level__lt=0.6).count(),
            'learning_count': profiles.filter(learning_status='learning').count(),
            'insights': insights,
            'weak_points': weak_points,
            'need_review': need_review,
        })

        return context


class KnowledgePointDetailView(LoginRequiredMixin, DetailView):
    """单个知识点详情页面"""
    model = KnowledgeMasteryProfile
    template_name = 'analysis/knowledge_point_detail.html'
    context_object_name = 'profile'

    # 通过 Django 的通用视图系统自动调用：
    """
    # Django 内部的大致调用顺序
    KnowledgePointDetailView.as_view() 
    → dispatch() 
    → get() 
    → get_object() 
    → get_queryset() 
    """
    def get_queryset(self):
        return KnowledgeMasteryProfile.objects.filter(
            student=self.request.user.student
        ).select_related('knowledge_point', 'knowledge_point__subject')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)  # **kwargs指定的是特定的ID
        profile = self.object

        analysis_service = AnalysisService()

        # 计算边际收益
        marginal_gain = analysis_service.calculate_marginal_gain(
            profile.student, profile.knowledge_point
        )

        # 获取练习记录
        practices = KnowledgePracticeRecord.objects.filter(
            student=profile.student,
            knowledge_point=profile.knowledge_point
        ).select_related('exam_record').order_by('-practiced_at')[:20]

        # 计算练习统计
        practice_stats = {
            'total_practices': practices.count(),
            'correct_practices': practices.filter(result='correct').count(),
            'recent_accuracy': 0,
        }

        if practices.exists():
            recent_practices = practices[:5]
            recent_correct = recent_practices.filter(result='correct').count()
            practice_stats['recent_accuracy'] = recent_correct / len(recent_practices) if recent_practices else 0

        # 获取关联知识点
        from analysis.models import KnowledgeRelationship
        related_knowledge = KnowledgeRelationship.objects.filter(
            source_knowledge=profile.knowledge_point
        ).select_related('target_knowledge')[:10]

        context.update({
            'marginal_gain': marginal_gain,
            'practices': practices,
            'practice_stats': practice_stats,
            'related_knowledge': related_knowledge,
        })

        return context


class WeakPointsListView(LoginRequiredMixin, ListView):
    """薄弱知识点列表"""
    template_name = 'analysis/weak_points_list.html'
    context_object_name = 'weak_points'
    paginate_by = 20

    def get_queryset(self):
        student = self.request.user.student
        profile_service = ProfileService()

        # 获取阈值参数
        threshold = float(self.request.GET.get('threshold', 0.6))

        return profile_service.get_weak_points(student, threshold).select_related(
            'knowledge_point', 'knowledge_point__subject'
        )

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        student = self.request.user.student

        profile_service = ProfileService()
        weak_points = self.get_queryset()

        # 按科目统计
        subject_stats = {}
        for point in weak_points:
            subject_name = point.knowledge_point.subject.name
            if subject_name not in subject_stats:
                subject_stats[subject_name] = 0
            subject_stats[subject_name] += 1

        context.update({
            'threshold': self.request.GET.get('threshold', 0.6),
            'total_weak_points': weak_points.count(),
            'subject_stats': subject_stats,
        })

        return context


class SubjectProfileView(LoginRequiredMixin, TemplateView):
    """科目维度知识点画像"""
    template_name = 'analysis/subject_profile.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        student = self.request.user.student
        subject_id = self.kwargs.get('subject_id')

        # 获取科目
        subject = get_object_or_404(Subject, id=subject_id)

        profile_service = ProfileService()
        analysis_service = AnalysisService()

        # 获取该科目的所有知识点画像
        profiles = KnowledgeMasteryProfile.objects.filter(
            student=student,
            knowledge_point__subject=subject
        ).select_related('knowledge_point').order_by('mastery_level')

        # 科目分析报告
        subject_analysis = analysis_service.analyze_subject_status(student, subject)

        # 掌握度分布
        mastery_distribution = {
            'excellent': profiles.filter(mastery_level__gte=0.8).count(),
            'good': profiles.filter(mastery_level__gte=0.6, mastery_level__lt=0.8).count(),
            'average': profiles.filter(mastery_level__gte=0.4, mastery_level__lt=0.6).count(),
            'poor': profiles.filter(mastery_level__lt=0.4).count(),
        }

        # 学习状态分布
        status_distribution = {
            'not_started': profiles.filter(learning_status='not_started').count(),
            'learning': profiles.filter(learning_status='learning').count(),
            'reviewing': profiles.filter(learning_status='reviewing').count(),
            'mastered': profiles.filter(learning_status='mastered').count(),
            'struggling': profiles.filter(learning_status='struggling').count(),
        }

        context.update({
            'subject': subject,
            'profiles': profiles,
            'subject_analysis': subject_analysis,
            'mastery_distribution': mastery_distribution,
            'status_distribution': status_distribution,
            'total_points': profiles.count(),
        })

        return context


class LearningProgressView(LoginRequiredMixin, TemplateView):
    """学习进度追踪"""
    template_name = 'analysis/learning_progress.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        student = self.request.user.student

        # 获取时间范围参数
        days = int(self.request.GET.get('days', 30))
        start_date = timezone.now() - timezone.timedelta(days=days)

        # 获取学习活动记录
        practices = KnowledgePracticeRecord.objects.filter(
            student=student,
            practiced_at__gte=start_date
        ).select_related('knowledge_point', 'knowledge_point__subject')

        # 按日期统计
        daily_stats = {}
        for practice in practices:
            date_str = practice.practiced_at.strftime('%Y-%m-%d')
            if date_str not in daily_stats:
                daily_stats[date_str] = {
                    'total': 0,
                    'correct': 0,
                    'subjects': set()
                }
            daily_stats[date_str]['total'] += 1
            if practice.result == 'correct':
                daily_stats[date_str]['correct'] += 1
            daily_stats[date_str]['subjects'].add(practice.knowledge_point.subject.name)

        # 转换为前端需要的格式
        learning_activities = []
        for date_str, stats in sorted(daily_stats.items()):
            learning_activities.append({
                'date': date_str,
                'total_practices': stats['total'],
                'accuracy': stats['correct'] / stats['total'] if stats['total'] > 0 else 0,
                'subjects_count': len(stats['subjects']),
            })

        # 总体统计
        total_stats = {
            'total_practices': practices.count(),
            'correct_practices': practices.filter(result='correct').count(),
            'subjects_covered': practices.values('knowledge_point__subject').distinct().count(),
            'knowledge_points_covered': practices.values('knowledge_point').distinct().count(),
            'study_days': len(daily_stats),
        }

        context.update({
            'learning_activities': learning_activities,
            'total_stats': total_stats,
            'days': days,
            'start_date': start_date.date(),
        })

        return context


class PracticeHistoryView(LoginRequiredMixin, ListView):
    """练习历史记录"""
    template_name = 'analysis/practice_history.html'
    context_object_name = 'practices'
    paginate_by = 25

    def get_queryset(self):
        student = self.request.user.student

        # 获取筛选参数
        knowledge_point_id = self.request.GET.get('knowledge_point')
        result_filter = self.request.GET.get('result')
        subject_id = self.request.GET.get('subject')

        queryset = KnowledgePracticeRecord.objects.filter(
            student=student
        ).select_related(
            'knowledge_point',
            'knowledge_point__subject',
            'exam_record'
        ).order_by('-practiced_at')

        # 应用筛选
        if knowledge_point_id:
            queryset = queryset.filter(knowledge_point_id=knowledge_point_id)
        if result_filter:
            queryset = queryset.filter(result=result_filter)
        if subject_id:
            queryset = queryset.filter(knowledge_point__subject_id=subject_id)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        student = self.request.user.student

        # 获取筛选选项
        subjects = Subject.objects.all()

        # 方案1：通过练习记录获取知识点
        practice_records = KnowledgePracticeRecord.objects.filter(student=student)
        knowledge_point_ids = practice_records.values_list('knowledge_point_id', flat=True).distinct()
        knowledge_points = KnowledgePoint.objects.filter(id__in=knowledge_point_ids)

        # 或者方案2：如果上面的方法不行，获取所有知识点
        # knowledge_points = KnowledgePoint.objects.all()

        context.update({
            'subjects': subjects,
            'knowledge_points': knowledge_points,
            'result_choices': KnowledgePracticeRecord.PRACTICE_RESULT_CHOICES,
            'current_filters': {
                'knowledge_point': self.request.GET.get('knowledge_point'),
                'result': self.request.GET.get('result'),
                'subject': self.request.GET.get('subject'),
            }
        })

        return context


@method_decorator(csrf_exempt, name='dispatch')
class UpdateProfileAfterExamView(LoginRequiredMixin, View):
    """考试后更新知识点画像 - API接口"""

    def post(self, request, exam_record_id):
        """
        考试后更新知识点画像
        POST /analysis/update-after-exam/<exam_record_id>/
        """
        try:
            student = request.user.student
            exam_record = get_object_or_404(ExamRecord, id=exam_record_id, student=student)

            # 检查考试记录是否已完成（可选）
            if not exam_record.is_completed:
                return JsonResponse({
                    'success': False,
                    'message': '考试记录尚未完成，无法更新知识点画像'
                }, status=400)

            loss_details = ScoreLossDetail.objects.filter(exam_record=exam_record)

            if not loss_details.exists():
                return JsonResponse({
                    'success': False,
                    'message': '该考试记录没有失分详情，无法更新知识点画像',
                    'code': 'NO_LOSS_DETAILS'
                }, status=400)

            # 检查是否已经更新过（防止重复更新）
            if hasattr(exam_record, 'profile_updated') and exam_record.profile_updated:
                return JsonResponse({
                    'success': False,
                    'message': '该考试记录的知识点画像已经更新过',
                    'code': 'ALREADY_UPDATED'
                }, status=400)

            # 调用Service更新画像
            profile_service = ProfileService()
            updated_profiles = profile_service.update_mastery_from_exam(
                student, exam_record, loss_details
            )

            # 标记考试记录已更新（可选）
            # exam_record.profile_updated = True
            # exam_record.profile_updated_at = timezone.now()
            # exam_record.save()

            return JsonResponse({
                'success': True,
                'message': f'成功更新 {len(updated_profiles)} 个知识点画像',
                'updated_count': len(updated_profiles),
                'exam_record_id': exam_record_id,
                'updated_profiles': [
                    {
                        'id': profile.id,
                        'knowledge_point': profile.knowledge_point.name,
                        'new_mastery_level': profile.mastery_level,
                        'previous_mastery_level': getattr(profile, '_previous_mastery_level', 'N/A')
                    } for profile in updated_profiles
                ],
                'redirect_url': reverse('analysis:profile_dashboard')
            })

        except ExamRecord.DoesNotExist:
            return JsonResponse({
                'success': False,
                'message': '考试记录不存在或无权访问',
                'code': 'EXAM_RECORD_NOT_FOUND'
            }, status=404)
        except Exception as e:
            # 记录错误日志
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"更新知识点画像失败: {str(e)}", exc_info=True)

            return JsonResponse({
                'success': False,
                'message': f'更新失败: {str(e)}',
                'code': 'UPDATE_FAILED'
            }, status=500)


class ProfileStatisticsView(LoginRequiredMixin, TemplateView):
    """画像统计信息"""
    template_name = 'analysis/profile_statistics.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        student = self.request.user.student

        profile_service = ProfileService()
        profiles = profile_service.get_student_profile(student)

        # 基础统计
        total_points = profiles.count()
        avg_mastery = profiles.aggregate(avg=Avg('mastery_level'))['avg'] or 0

        # 掌握度分布
        mastery_ranges = [
            (0.8, 1.0, '优秀'),
            (0.6, 0.8, '良好'),
            (0.4, 0.6, '一般'),
            (0.0, 0.4, '薄弱'),
        ]

        mastery_distribution = []
        for min_val, max_val, label in mastery_ranges:
            count = profiles.filter(
                mastery_level__gte=min_val,
                mastery_level__lt=max_val
            ).count()
            percentage = (count / total_points * 100) if total_points > 0 else 0
            mastery_distribution.append({
                'range': label,
                'count': count,
                'percentage': round(percentage, 1)
            })

        # 学习状态统计
        status_stats = []
        for status_code, status_name in KnowledgeMasteryProfile.LEARNING_STATUS_CHOICES:
            count = profiles.filter(learning_status=status_code).count()
            percentage = (count / total_points * 100) if total_points > 0 else 0
            status_stats.append({
                'status': status_name,
                'count': count,
                'percentage': round(percentage, 1)
            })

        # 科目维度统计
        subject_stats = []
        subjects = Subject.objects.all()
        for subject in subjects:
            subject_profiles = profiles.filter(knowledge_point__subject=subject)
            if subject_profiles.exists():
                subject_avg = subject_profiles.aggregate(avg=Avg('mastery_level'))['avg'] or 0
                subject_stats.append({
                    'subject': subject.name,
                    'total_points': subject_profiles.count(),
                    'avg_mastery': round(subject_avg, 3),
                    'color': subject.color
                })

        # 趋势分析
        improving_count = profiles.filter(mastery_trend='improving').count()
        declining_count = profiles.filter(mastery_trend='declining').count()

        context.update({
            'total_knowledge_points': total_points,
            'avg_mastery': round(avg_mastery, 3),
            'mastery_distribution': mastery_distribution,
            'status_stats': status_stats,
            'subject_stats': subject_stats,
            'trend_stats': {
                'improving': improving_count,
                'declining': declining_count,
                'stable': total_points - improving_count - declining_count,
            }
        })

        return context